package ffte.core.streamed

import spinal.core._
import spinal.lib._

import ffte.types.VecComplex
import ffte.property.{getFFTIW,getFFTOW,FFTIOConfig}
import ffte.algorithm.FFTGen.{psbFFT}

/**
 * Streamed Prime-Space Block (PSB) FFT implementation
 *
 * This class implements FFT using the Prime-Space Block decomposition method
 * with fully streamed architecture. The streamed PSB processes data through
 * a pipeline with flow control, enabling continuous high-throughput processing.
 *
 * Mathematical Foundation:
 * The PSB method decomposes an N-point DFT where N = N1 * N2 with gcd(N1, N2) = 1.
 * Using the Chinese Remainder Theorem, the transform can be separated into
 * two independent stages without requiring twiddle factor multiplication.
 *
 * Streamed PSB Architecture:
 * - First stage: N2 independent N1-point streamed FFTs
 * - Interleaver: Data reordering based on CRT mapping
 * - Second stage: N1 independent N2-point streamed FFTs
 * - No twiddle factors required due to coprime decomposition
 *
 * Performance Characteristics:
 * - Optimal for coprime factorizations
 * - Minimal multiplication count (no twiddle factors)
 * - High throughput through pipelined processing
 * - Regular memory access patterns
 *
 * @tparam T Streamed method type parameter
 * @param S Scaling shift amount for fixed-point overflow prevention
 * @param p PSB decomposition structure containing stage information and mapping tables
 */
class psb[T <: Streamed](val S: Int, val p: psbFFT[T]) extends combineStreamedComponents[T] {
    /**
     * Second stage processing block
     *
     * This block implements the second stage of the PSB decomposition,
     * consisting of N1 independent N2-point streamed FFTs operating
     * in parallel. Each FFT processes the reordered intermediate data
     * according to the Chinese Remainder Theorem mapping.
     *
     * Architecture:
     * - N1 parallel streamed FFT processors of size N2
     * - Input width: interW (intermediate precision)
     * - Output width: oW (global output precision)
     * - Streaming interface with flow control
     */
    val s_block = FFTIOConfig(interW, oW) on new Area {
        /**
         * Second stage streamed FFT processors
         *
         * Creates N1 independent streamed FFT processors using the
         * Streamed method with second stage scaling.
         */
        val u = sg(second, "s")
        val delay = u.delay
    }

    /**
     * Streamed interleaver for data reordering
     *
     * Implements the Chinese Remainder Theorem-based data reordering
     * required between the two PSB stages. This interleaver handles
     * the complex index mapping in the streaming domain.
     *
     * Function:
     * - Routes data from first stage outputs to second stage inputs
     * - Implements CRT index permutation: (i*N2 + j) → mapping
     * - Maintains streaming semantics and flow control
     *
     * Configuration:
     * - Width: interW bits (intermediate precision)
     * - First dimension: first.N samples
     * - Second dimension: second.N samples
     */
    val interleave = SInterleaver(interW, first.N, second.N)

    /**
     * Pipeline connections
     *
     * Data flows through the PSB pipeline:
     * 1. First stage FFT (f_block)
     * 2. CRT interleaver
     * 3. Second stage FFT (s_block)
     */
    f_block.u.io.q >> interleave.io.d    // First stage to interleaver
    interleave.io.q >> s_block.u.io.d   // Interleaver to second stage

    /**
     * External I/O connections
     *
     * Input data flows to the first stage and output data comes
     * from the second stage of the pipeline.
     */
    io.d >> f_block.u.io.d              // Input to first stage
    io.q << s_block.u.io.q              // Output from second stage

    /**
     * Total pipeline delay in clock cycles
     *
     * Total delay includes:
     * - First stage FFT delay (f_block.delay)
     * - Interleaver delay for data reordering (interleave.delay)
     * - Second stage FFT delay (s_block.delay)
     *
     * @return Total delay from input to output in clock cycles
     */
    def delay = f_block.delay + interleave.delay + s_block.delay
}